﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace SmartMathLibrary.Space
{
    /// <summary>
    /// This class represents a space object.
    /// </summary>
    [Serializable]
    public class SpaceItem : IComparable, ICloneable, ISerializable
    {
        /// <summary>
        /// This field holds the space object ID.
        /// </summary>
        private readonly uint id;

        /// <summary>
        /// This field holds the lock status.
        /// </summary>
        private bool locked;

        /// <summary>
        /// This field holds the value of the space object.
        /// </summary>
        private ISpaceEntry value;

        /// <summary>
        /// Initializes a new instance of the <see cref="SpaceItem"/> class.
        /// </summary>
        /// <param name="id">The ID of the space object.</param>
        /// <param name="value">The value of the space object.</param>
        public SpaceItem(uint id, ISpaceEntry value)
        {
            this.id = id;
            this.value = value;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SpaceItem"/> class.
        /// </summary>
        /// <param name="info">The specified serialization information.</param>
        /// <param name="ctx">The specified streaming context.</param>
        public SpaceItem(SerializationInfo info, StreamingContext ctx)
        {
            if (info == (SerializationInfo) null)
            {
                throw new ArgumentNullException("info");
            }

            this.id = info.GetUInt32("id");
            this.locked = info.GetBoolean("locked");
            this.value = (ISpaceEntry) info.GetValue("value", typeof (ISpaceEntry));
        }

        /// <summary>
        /// Populates a System.Runtime.Serialization. SerializationInfo with the data needed 
        /// to serialize the target object.
        /// </summary>
        /// <param name="info">The specified serialization information.</param>
        /// <param name="ctx">The specified streaming context.</param>
        public void GetObjectData(SerializationInfo info, StreamingContext ctx)
        {
            info.AddValue("id", this.id, typeof (uint));
            info.AddValue("locked", this.locked, typeof (bool));
            info.AddValue("value", this.value, typeof (ISpaceEntry));
        }

        /// <summary>
        /// Gets the space object ID.
        /// </summary>
        /// <value>The space object ID.</value>
        public uint Id
        {
            get { return id; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="SpaceItem"/> is locked.
        /// </summary>
        /// <value>True if locked otherwise, false.</value>
        public bool Locked
        {
            get { return locked; }
            set { locked = value; }
        }

        /// <summary>
        /// Gets or sets the value of the space object.
        /// </summary>
        /// <value>The value of the space object.</value>
        public ISpaceEntry Value
        {
            get { return this.value; }
            set { this.value = value; }
        }

        /// <summary>
        /// Compares the current instance with another object of the same type.
        /// </summary>
        /// <param name="obj">An object to compare with this instance.</param>
        /// <returns>
        /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance is less than <paramref name="obj"/>. Zero This instance is equal to <paramref name="obj"/>. Greater than zero This instance is greater than <paramref name="obj"/>.
        /// </returns>
        /// <exception cref="T:System.ArgumentException">
        /// 	<paramref name="obj"/> is not the same type as this instance. </exception>
        public int CompareTo(object obj)
        {
            if (obj is SpaceItem)
            {
                if (this.id < ((SpaceItem) obj).id)
                {
                    return -1;
                }

                if (this.id > ((SpaceItem) obj).id)
                {
                    return 1;
                }

                return 0;
            }

            throw new ArgumentException("Object has to be of typ SpaceItem.");
        }

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
        public object Clone()
        {
            return new SpaceItem(this.id, (ISpaceEntry) this.value.Clone());
        }
    }
}